package com.xplay.xpocker.meta.realize;

import com.fasterxml.jackson.annotation.JsonFormat;
import com.xplay.xpocker.entity.mahjong.*;
import com.xplay.xpocker.entity.system.DissolutionEntity;
import com.xplay.xpocker.meta.room.MetaRoomEntity;
import com.xplay.xpocker.util.CardUtil;
import com.xplay.xpocker.util.DictionaryConst;
import lombok.Data;

import java.io.Serializable;
import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.stream.Collectors;

import static com.xplay.xpocker.util.DictionaryConst.MahjongAction.CARD_BAR;
import static com.xplay.xpocker.util.DictionaryConst.MahjongAction.EXPORT_CARD;

/**
 * 注意 在玩家退出 的时候需要去维护 UserMetaChannel   中的 seq 序列
 * 以及 内存中  存储的房间用户序列   ！！！！！！！！！！！！！！！！
 *
 * @author wanjie
 * @date 2021/3/17 20:02
 */

@Data
public class MahjongRoomEntity extends MetaRoomEntity<MahjongRoomEntity, MahjongRule, MahjongUserChannel> implements Serializable {
    private static final long serialVersionUID = -4685653638406158228L;
    // 庄家的序列
    private Integer bankerIndex;
    // 当前出牌玩家的序列
    private String currentExportUserId;
    // 当前出牌是什么
    private Integer currentExportCard;
    // 当前摸的牌是什么
    private Integer licensingCard;
    // 如果有人杠牌的话 这个对象不会为空
    private MahjongUserChannel currentBarUser;
    // 当前局数
    private int gamesCurrentNumber = 1;

    // 房间创建时间
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm", timezone = "GMT+8")
    private Date createDate;
    // 游戏开始时间
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm", timezone = "GMT+8")
    private Date gameStartDate;
    // 游戏结束时间
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm", timezone = "GMT+8")
    private Date gameEndDate;

    // 游戏开始时间
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm", timezone = "GMT+8")
    private LocalDateTime currentGameStartDate;
    // 游戏结束时间
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm", timezone = "GMT+8")
    private Date currentGameEndDate;
    // 麻将
    private CopyOnWriteArrayList<Integer> allCard;
    // 交换骰子的数字
    private Integer exchangeValue;
    // 房间状态
    private int state;

    private MahjongRule rule;

    private DissolutionEntity dissolutionEntity;

    public MahjongRule getRule() {
        if (rule == null) {
            this.rule = this.getRoomRule(MahjongRule.class);
        }
        return this.rule;
    }

    // 当前用户的手牌
    private CopyOnWriteArrayList<Integer> currentUserCards;


    // 玩家的 碰杠信息
    private HashMap<String, ArrayList<MahjongCardTouchBar>> userTouchBar;

    // 其它玩家的信息
    private HashMap<String, MahjongOtherInfo> otherUserInfo;

    // 当前用户碰牌的手牌
    private CopyOnWriteArrayList<Integer> currentUserTouchBarCards;

    // 玩家手牌
    private HashMap<String, CopyOnWriteArrayList<Integer>> userCards;
    // 玩家交换的牌
    private HashMap<String, CopyOnWriteArrayList<Integer>> userExchangeCards;

    // 玩家已经出了的牌
    private HashMap<String, CopyOnWriteArrayList<Integer>> userExportCards;

    // 玩家交换信息
    private HashMap<String, UserSwapCard> userSwapInfo;


    //  当前局结算信息
    private ArrayList<MahjongBillClearing> billClearingInfo;

    // 房间任务信息
    private ArrayList<MahjongUserTask> roomTask;

    private MahjongUserTask currentUserTask;

    // 玩家胡牌信息
    private List<MahjongBillEntity> currentGameBillHistory;


    private MahjongUserChannel currentUserInfo;

    private int allCardCount;

    private Integer exportCardCount;


    public Integer getExportCardCount() {
        Integer result = 0;
        if (this.userExportCards == null) {
            return result;
        }
        for (Map.Entry<String, CopyOnWriteArrayList<Integer>> entry : this.userExportCards.entrySet()) {
            if (entry.getValue() != null) {
                result += entry.getValue().size();
            }
        }
        return result;
    }

    /**
     * 获取用户所有的牌
     * <p>
     * 用于结算展示
     *
     * @return
     */

    public CopyOnWriteArrayList<Integer> getUserAllCards(String userId) {
        CopyOnWriteArrayList<Integer> result = new CopyOnWriteArrayList<Integer>();
        CopyOnWriteArrayList<Integer> userCards = this.userCards.get(userId);
        result.addAll(userCards);
        ArrayList<MahjongCardTouchBar> cardTouchBars = null != this.userTouchBar ? this.userTouchBar.get(userId) : null;
        if (cardTouchBars != null) {
            for (MahjongCardTouchBar touchBar : cardTouchBars) {
                result.addAll(touchBar.getCards());
            }
        }
        MahjongUserChannel mahjongUserChannel = this.allUserInfo.get(userId);
        if (mahjongUserChannel.isWin()) {
            if (null != mahjongUserChannel.getHuCard()) {
                result.add(mahjongUserChannel.getHuCard());
            }
        }
        result.sort(Comparator.naturalOrder());
        return result;
    }

    /**
     * 添加胡牌人
     */
    public void addBillClearingInfo(MahjongUserChannel userInfo, boolean isWin) {
        if (this.billClearingInfo == null) {
            this.billClearingInfo = new ArrayList<>();
        }
        MahjongBillClearing billClearing = new MahjongBillClearing(userInfo, isWin);
        billClearing.setUserWinSeq(this.billClearingInfo.size() + 1);
        billClearingInfo.add(billClearing);
    }

    /**
     * 添加胡牌详情单
     *
     * @param billEntity
     */
    public void addBillHistory(MahjongBillEntity billEntity) {
        if (this.currentGameBillHistory == null) {
            this.currentGameBillHistory = new ArrayList<>();
        }
        this.currentGameBillHistory.add(billEntity);

    }

    /**
     * 检查用户是否 有杠牌
     *
     * @param userChannel
     * @return
     */


    public ArrayList<Integer> checkUserBar(MahjongUserChannel userChannel) {
        ArrayList<Integer> result = null;
        CopyOnWriteArrayList<Integer> userCards = this.getUserCards().get(userChannel.getUserId());
        ArrayList<Integer> barList = CardUtil.checkCardNumber(userCards, 4);
        if (barList.size() >= 1) {
            result = barList;
        }
        // 如果是 发牌的话这里还需要判断巴杠 将手里的牌全部取出来 然后到碰牌里面做判断
        ArrayList<Integer> userAllTouchBarCards = this.getUserAllTouchBarCards(userChannel.getUserId());
        if (null != userAllTouchBarCards && userAllTouchBarCards.size() > 0) {
            for (Integer cardTemp : userCards) {
                if (Collections.frequency(userAllTouchBarCards, cardTemp) == 3) {
                    if (result == null) {
                        result = new ArrayList<>();
                    }
                    result.add(cardTemp);
                }
            }
        }
        return result;
    }

    public CopyOnWriteArrayList<Integer> getCurrentUserCard(String userId) {
        try {
            CopyOnWriteArrayList<Integer> userCards = this.getUserCards().get(userId);
            return userCards == null ? new CopyOnWriteArrayList<>() : userCards;
        } catch (Exception e) {
            return new CopyOnWriteArrayList<>();
        }
    }

    public Integer allCardLength() {
        if (this.allCard == null) {
            return 0;
        } else {
            return this.allCard.size();
        }


    }

    public boolean checkFistAndLastFour() {
        return this.getRule().getRules().contains(DictionaryConst.MahjongRuleConst.SING_UP) && (this.getExportCardCount() <= 3 || this.getAllCard().size() <= 3);
    }


    public void setUserGameTypeStart() {
        HashMap<String, MahjongUserChannel> userMaps = this.getAllUserInfo();
        Set<Map.Entry<String, MahjongUserChannel>> entrys = userMaps.entrySet();
        for (Map.Entry<String, MahjongUserChannel> entry : entrys) {
            entry.getValue().setGameType(DictionaryConst.MahjongRoomState.START);
        }
    }


    public void setCurrentUserCards(CopyOnWriteArrayList<Integer> currentUserCards) {
        if (currentUserCards != null) {
            currentUserCards.sort(Comparator.naturalOrder());
        }
        this.currentUserCards = currentUserCards;
    }

    public ArrayList<MahjongUserTask> getOtherUserTask(String userId) {
        ArrayList<MahjongUserTask> result = new ArrayList<MahjongUserTask>();
        if (null == this.getRoomTask()) {
            return null;
        }
        ArrayList<MahjongUserTask> roomTask = this.getRoomTask();
        for (MahjongUserTask userTask : roomTask) {
            if (!userTask.getUserId().equals(userId)) {
                result.add(userTask);
            }
        }
        return result;
    }

    public MahjongUserTask getUserTask(String userId) {
        if (null == this.getRoomTask()) {
            return null;
        }
        ArrayList<MahjongUserTask> roomTask = this.getRoomTask();
        for (MahjongUserTask userTask : roomTask) {
            if (userTask.getUserId().equals(userId) && !userTask.isDealWith()) {
                return userTask;
            }
        }
        return null;
    }

    public Integer notDealWithTask() {
        Integer result = 0;
        if (null == this.getRoomTask()) {
            return result;
        }
        ArrayList<MahjongUserTask> roomTask = this.getRoomTask();
        for (MahjongUserTask userTask : roomTask) {
            if (!userTask.isDealWith()) {
                result++;
            }
        }
        return result;
    }

    public ArrayList<MahjongCardTouchBar> getUserTouchBarCards(String userId) {
        HashMap<String, ArrayList<MahjongCardTouchBar>> roomInfoUserTouchBar = this.getUserTouchBar();
        if (null == roomInfoUserTouchBar) {
            roomInfoUserTouchBar = new HashMap<String, ArrayList<MahjongCardTouchBar>>();
            this.setUserTouchBar(roomInfoUserTouchBar);
        }
        ArrayList<MahjongCardTouchBar> cardTouchBars = roomInfoUserTouchBar.get(userId);
        if (null == cardTouchBars) {
            cardTouchBars = new ArrayList<MahjongCardTouchBar>();
            roomInfoUserTouchBar.put(userId, cardTouchBars);
        }
        return cardTouchBars;
    }

    public MahjongCardTouchBar getUserTouchBarByCardId(String userId, Integer cardId) {
        MahjongCardTouchBar result = null;
        ArrayList<MahjongCardTouchBar> userTouchBarCards = getUserTouchBarCards(userId);
        for (MahjongCardTouchBar userTouchBarCard : userTouchBarCards) {
            if (userTouchBarCard.getCards().get(0) == cardId) {
                if (result != null) {
                    break;
                }
                result = userTouchBarCard;
            }
        }
        return result;
    }


    public ArrayList<Integer> getUserAllTouchBarCards(String userId) {
        ArrayList<Integer> result = new ArrayList<Integer>();
        ArrayList<MahjongCardTouchBar> touchBarCards = getUserTouchBarCards(userId);
        if (null != touchBarCards && touchBarCards.size() > 0) {
            for (MahjongCardTouchBar barCard : touchBarCards) {
                if (null != barCard.getCards() && barCard.getCards().size() > 0)
                    barCard.getCards().forEach(val -> {
                        result.add(val);
                    });
            }
        }
        return result;
    }


    public void cleanUserTask(String userId, String action) {
        if (null == this.getRoomTask()) {
            return;
        }
        ArrayList<MahjongUserTask> roomTask = this.getRoomTask();
        if (null != roomTask) {
            Iterator<MahjongUserTask> taskIterator = roomTask.iterator();
            while (taskIterator.hasNext()) {
                MahjongUserTask userTask = taskIterator.next();
                if (userTask.getUserId().equals(userId) && null != userTask.getTaskArray() && userTask.getTaskArray().contains(action)) {
                    userTask.getTaskArray().remove(action);
                }
            }
        }
    }

    public void cleanUserTask(String userId) {
        if (null == this.getRoomTask()) {
            return;
        }
        ArrayList<MahjongUserTask> roomTask = this.getRoomTask();
        if (null != roomTask) {
            Iterator<MahjongUserTask> taskIterator = roomTask.iterator();
            while (taskIterator.hasNext()) {
                MahjongUserTask userTask = taskIterator.next();
                if (userTask.getUserId().equals(userId)) {
                    taskIterator.remove();
                }
            }
        }
    }

    public MahjongUserTask getUserTask(String userId, String action) {
        if (null == this.getRoomTask()) {
            return null;
        }
        ArrayList<MahjongUserTask> roomTask = this.getRoomTask();
        for (MahjongUserTask userTask : roomTask) {
            if (userTask.getUserId().equals(userId)) {
                CopyOnWriteArrayList<String> taskArray = userTask.getTaskArray();
                if (taskArray != null && taskArray.size() > 0 && taskArray.contains(action)) {
                    return userTask;
                }
                if (null != userTask.getTask() && userTask.getTask().equals(action)) {
                    return userTask;
                }
            }
        }
        return null;
    }

    public void setUserCards(HashMap<String, CopyOnWriteArrayList<Integer>> userCards) {
        if (userCards != null) {
            for (Map.Entry<String, CopyOnWriteArrayList<Integer>> entry : userCards.entrySet()) {
                entry.getValue().sort(Comparator.naturalOrder());
            }
        }
        this.userCards = userCards;
    }

    public void addNewTask(MahjongUserTask userTask) {
        this.roomTask = null;
        userTask.setDealWith(false);
        this.addTask(userTask);
    }

    public void upUserWin(String userId) {
        this.getAllUserInfo().get(userId).setWin(true);
    }

    public List<MahjongUserChannel> notWinnerUsers() {
        ArrayList<MahjongUserChannel> result = new ArrayList<MahjongUserChannel>();
        HashMap<String, MahjongUserChannel> userMaps = this.getAllUserInfo();
        Set<Map.Entry<String, MahjongUserChannel>> entrys = userMaps.entrySet();
        for (Map.Entry<String, MahjongUserChannel> entry : entrys) {
            if (!entry.getValue().isWin()) {
                result.add(entry.getValue());
            }
        }
        return result;
    }


    public int notWinnerSum() {
        int result = 0;
        HashMap<String, MahjongUserChannel> userMaps = this.getAllUserInfo();
        Set<Map.Entry<String, MahjongUserChannel>> entrys = userMaps.entrySet();
        for (Map.Entry<String, MahjongUserChannel> entry : entrys) {
            if (!entry.getValue().isWin()) {
                result++;
            }
        }
        return result;
    }

    /**
     * 为用户添加任务
     *
     * @param userTask
     */
    public void addTask(MahjongUserTask userTask) {
        boolean hasTask = false;
        ArrayList<MahjongUserTask> roomTask = this.getRoomTask();
        if (null == roomTask) {
            roomTask = new ArrayList<MahjongUserTask>();
            this.setRoomTask(roomTask);
        }
        for (MahjongUserTask task : roomTask) {
            if (task.getUserId().equals(userTask.getUserId())) {
                hasTask = true;
                CopyOnWriteArrayList<String> taskArray = task.getTaskArray();
                if (null == taskArray) {
                    taskArray = new CopyOnWriteArrayList<>();
                    task.setTaskArray(taskArray);
                    taskArray.add(task.getTask());
                    if (!task.getTask().equals(userTask.getTask())) {
                        taskArray.add(userTask.getTask());
                    }
                } else if (taskArray != null && userTask.getTaskArray() != null) {
                    for (String item : userTask.getTaskArray()) {
                        if (!taskArray.contains(item)) {
                            taskArray.add(item);
                        }
                    }
                } else {
                    if (!taskArray.stream().anyMatch(item -> item.equals(userTask.getTask()))) {
                        taskArray.add(userTask.getTask());
                    }
                }
                task.setTask(null);
            }
        }
        if (!hasTask) {
            roomTask.add(userTask);
        }
    }

    public MahjongUserChannel getUserInfoBySeq(Integer seq) {
        if (seq == null) {
            return null;
        }
        HashMap<String, MahjongUserChannel> userInfoMaps = this.getAllUserInfo();
        for (Map.Entry<String, MahjongUserChannel> user : userInfoMaps.entrySet()) {
            if (user.getValue().getSeq() == seq) {
                return user.getValue();
            }
        }
        return null;
    }


    public MahjongUserChannel queryUserBanker() {
        HashMap<String, MahjongUserChannel> userInfoMaps = this.getAllUserInfo();
        if (null == userInfoMaps) {
            return null;
        }
        for (Map.Entry<String, MahjongUserChannel> user : userInfoMaps.entrySet()) {
            if (user.getValue().isBanker()) {
                return user.getValue();
            }
        }
        return null;
    }

    public MahjongUserChannel getUserInfoByUserId(String userId) {
        HashMap<String, MahjongUserChannel> userInfoMaps = this.getAllUserInfo();
        if (null == userInfoMaps) {
            return null;
        }
        for (Map.Entry<String, MahjongUserChannel> user : userInfoMaps.entrySet()) {
            if (user.getKey().equals(userId)) {
                return user.getValue();
            }
        }
        return null;
    }

    public MahjongRoomEntity initAllCard() {
        allCard = new CopyOnWriteArrayList<Integer>();
        for (int i = 1; i <= 27; i++) {
            for (int j = 1; j <= 4; j++) {
                allCard.add(i);
            }
        }
        Collections.shuffle(allCard);
        return this;
    }

    public MahjongRoomEntity() {
    }

    public MahjongRoomEntity(String code, Integer userCount, Date createDate) {
        this.code = code;
        this.createDate = createDate;
    }

    public MahjongRoomEntity(String code, Integer userCount, Date createDate, int gamesNumber) {
        this.code = code;
        this.createDate = createDate;
    }

    public void reInit() {
        this.userCards = null;
        this.userExchangeCards = null;
        this.userTouchBar = null;
        this.userExportCards = null;
        this.allCardCount = 0;
        this.roomTask = null;
        this.currentUserCards = null;
        this.allCard = null;
        this.exchangeValue = null;
        this.currentBarUser = null;
        this.currentExportCard = null;
        this.currentExportUserId = null;
        this.bankerIndex = null;
        HashMap<String, MahjongUserChannel> allUserInfo = this.getAllUserInfo();
        if (null != allUserInfo) {
            for (Map.Entry<String, MahjongUserChannel> userItem : allUserInfo.entrySet()) {
                MahjongUserChannel channel = userItem.getValue();
                channel.setWin(false);
                channel.setGameType(DictionaryConst.MahjongRoomState.CREATE);
                channel.setPrepare(false);
                channel.setHuCard(null);
                channel.setListening(false);
                channel.setFiringUser(null);
                channel.setUserSwapCard(null);
                channel.setCallHuCards(null);
            }
        }
        // 初始化所有棋牌
        initAllCard();
    }


    public void setUserBanker(String currentExportUserId) {
        HashMap<String, MahjongUserChannel> allUserInfo = this.getAllUserInfo();
        if (null != allUserInfo) {
            for (Map.Entry<String, MahjongUserChannel> userItem : allUserInfo.entrySet()) {
                MahjongUserChannel channel = userItem.getValue();
                if (channel.getUserId().equals(currentExportUserId)) {
                    channel.setBanker(true);
                } else {
                    channel.setBanker(false);
                }
            }
        }
    }
}
